library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;


entity trc_Unit is
	generic (
		Z : positive range 1 to 256 ;
		
		--Vecteurs de base
		N_alpha : positive ;
		
		R_beta1 : positive ;
                log2Rbeta2 : positive;
		N_beta1 : positive ;
		k_beta1 : positive ;
		
		N_beta2 : positive ;
		R_beta2 : positive ;
                log2Rbeta1 : positive;
		k_beta2 : positive ;
		
		e1 : positive ;       --Coefficiant form TRC (view enwikipedia TRC)
		e2 : positive ;       
		e3 : positive
	);
	port (
		clk	: in std_logic ;
		reset	: in std_logic ;
		in_alpha : in std_logic_vector(Z-1 downto 0) ;
		in_beta1 : in std_logic_vector(Z-1 downto 0) ;
		in_beta2 : in std_logic_vector(Z-1 downto 0) ;
		s  : out std_logic_vector(Z-1 downto 0)    
	);
end entity;

--------------------------------

architecture trc_Unit1 of trc_Unit is


component Mult_Montg_Unit is
generic(
	Z : positive range 1 to 256 ;		-- Nombre de bits du module
	N : positive ;	-- Vecteur de base utilisé
	R : positive ;	-- Plus proche puissance de 2 de N par valeur supérieure
        log2R : positive;
	k : positive 	-- Constante nécessaire au calcul
) ;
port (
	a : in std_logic_vector(Z-1 downto 0) ;	-- Entrée 1 multiplicateur (domaine de Montgomery)
	b : in std_logic_vector(Z-1 downto 0) ;	-- Entrée 2 multiplicateur (domaine de Montgomery)
	is_active : in std_logic ;		-- La MMU doit-elle fonctionner?

	clk : in std_logic ;	-- Signal d'horloge
	reset : in std_logic ;

	c : out std_logic_vector(Z-1 downto 0) ;	-- Sortie du multiplicateur (domaine de Montgomery)
	is_ready : out std_logic ;		-- La MMU est-elle prête à fonctionner?
	is_end : out std_logic		-- La MMU a-t-elle fini?
 ) ;
end component ;


component mod_Unit is
	generic(
		Z : positive range 1 to 256 ;
		N : positive 
	);
	port(
		clk	: in std_logic ;
		reset	: in std_logic ;
		s_in	: in std_logic_vector(Z-1 downto 0 ) ;
		
		s_out	: out std_logic_vector(Z-1 downto 0 ) ;
		b_fin	: out std_logic 
	);
end component ;

signal s_unsigned_in, s_unsigned_out : unsigned(4*Z-1 downto 0) ;

signal a1, a2, a3 : unsigned(2*Z-1 downto 0)  ;

signal a2_std,a3_std : std_logic_vector(Z-1 downto 0) ;

signal useless1, useless2, useless3, useless4, useless5 : std_logic ;


begin

	--Reconversion MM -> Reel : on multiplie par R^(-1) mod N (role de la MMU)   
	
	a1 <= resize( unsigned(in_alpha), 2*Z ) ;
	a2 <= resize( unsigned(a2_std), 2*Z) ;
	a3 <= resize( unsigned(a3_std), 2*Z) ;
	
	MMU_1 : Mult_Montg_Unit
	generic map(
		Z => Z ,	-- Nombre de bits du module
		N => N_beta1 ,	-- Vecteur de base utilise
		R => R_beta1 ,	-- Plus proche puissance de 2 de N par valeur superieure
                log2R => log2Rbeta1,
		k => k_beta1 	-- Constante necessaire au calcul
	)
	port map(
		a => in_beta1 ,
 		b =>  std_logic_vector( to_unsigned(1, Z) ) ,
		is_active => '1' , 
		clk => clk,
		reset => reset,
		c => a2_std ,
		is_ready => useless1 ,
		is_end => useless2 
	) ;
	
	MMU_2 : Mult_Montg_Unit
	generic map(
		Z => Z ,	-- Nombre de bits du module
		N => N_beta2 ,	-- Vecteur de base utilise
		R => R_beta2 ,	-- Plus proche puissance de 2 de N par valeur superieure
                log2R => log2Rbeta2,
		k => k_beta2 	-- Constante necessaire au calcul
	)
	port map(
		a => in_beta2 ,
		b => std_logic_vector( to_unsigned(1 ,Z ) ) ,
		is_active => '1' ,
		clk => clk,
		reset => reset,
		c => a3_std ,
		is_ready => useless3 ,
		is_end => useless4
	) ;
	
	s_unsigned_in <= resize( ( unsigned(a1)*e1 + unsigned(a2)*e2 + unsigned(a3)*e3 )  , 4*Z ) ;
	
	MOD_1 : mod_Unit
	generic map( Z => 4*Z , N => N_beta1*N_beta2*N_alpha ) 
	port map(
		clk => clk,
		reset => reset,
		s_in => std_logic_vector(s_unsigned_in),
		unsigned(s_out) => s_unsigned_out,
		b_fin => useless5
	) ;
	
	s <= std_logic_vector( resize( s_unsigned_out, Z ) ) ;
	
end trc_Unit1 ;

